//#define CXXOMFORT_NOTICES 2
#include <cxxomfort/cxxomfort.hpp>
#include <cxxomfort/any.hpp>
#include <cxxomfort/typeindex.hpp>
#include <cxxomfort/library/type_name.hpp>
#include <string>
#include <iostream>
#include <vector>
#include <print_traits.hpp>

#define HA(TID) type_index(TID).hash_code()

struct any_print {
	explicit any_print (std::ostream& os_)
	: os(os_)
	{}
	
	void operator() (std::any const& A) const {
		using namespace std;
		//cout<< "* any_print: A: "<< HA(A.type())<< endl;
		{
			size_t intcodes[] = {HA(typeid(int)), HA(typeid(short))} ;
			size_t uintcodes[] = {HA(typeid(unsigned int)), HA(typeid(unsigned short))} ;
			if (false) {
			}
			else if (find(begin(intcodes), end(intcodes), HA(A.type()) ) != end(intcodes) ) {
				os<< any_cast<int>(A);
			}
			else if (find(begin(uintcodes), end(uintcodes), HA(A.type()) ) != end(uintcodes) ) {
				os<< any_cast<unsigned int>(A);
			}
			else if (HA(A.type()) == HA(typeid(std::string))) {
				os<< any_cast<std::string>(A);
			}
			else if (HA(A.type()) == HA(typeid(std::string_view))) {
				cout<< any_cast<std::string_view>(A);
			}
			
			else {
				os<< "{unrecognized_any}";
			}
		}
		
	}
	
	std::ostream& os;
	
};

inline 
std::ostream& operator<< (std::ostream& os, std::any const& A) {
	any_print K(os);
	K(A);
	return os;
}

int main () {
	using namespace std;
	using cxxomfort::library::typeid_demangle;
	cxxomfort::output_info(stdout);
	cout<< endl;
	static_assert0( cxxomfort::is_std_any< any >::value);
	cout<<  "sizeof(any) : "<< sizeof(any)<< "\n";
	cout<< "std::any implementation info: ";
	cout<< CXXOMFORT_IMPLEMENTS_std_any<< "\n";
	cout<< "\n";
	any foo;
	try {
	cout<< "try:"<< endl;
	foo = 1;
	cout<< typeid_demangle(foo.type())<< " , "<< any_cast<int>(foo)<< endl;
	foo = 1.0f;
	cout<< typeid_demangle(foo.type())<< " , "<< any_cast<double>(foo)<< endl;
	
	return 0;
	
	} catch (std::exception& E) {
		cerr<< "Exception: "<< E.what()<< endl;
		cerr<< "Any: "<< foo.type().name()<< endl;
	}
	cout<< endl;

	any foo2(2.0);
	cout<< typeid_demangle(foo2.type())<< " , "<< any_cast<float>(&foo2)<< endl;
	
	try {
		cout<< "vector<any>: "<< endl;
		
		vector<any> VV;
		
		VV.push_back(10U); cout<< "1"<< flush;
		VV.push_back(reinterpret_cast<bool*>(0)); cout<< "2"<< flush;
		VV.push_back(cxxomfort::library::type_name<bool&>()); cout<< "3"<< flush;
		VV.push_back(wstring(L"ááá")); cout<< "4"<< flush;
		cout<< endl;
		
		for (unsigned i=0; i<VV.size(); ++i) {
			cout<< i<< ": \t"<< typeid_demangle(VV[i].type())<< endl;
			cout<< i<< ": \t"<< VV[i]<< endl;
		}
		
	} catch (std::exception& E) {
		cout<< E.what()<< endl;
	}
	
	cout<< "\n\n";
	cout<< "Test of assigning an array:"<< endl;
	any cs("Hello World");
	cout<< cxxomfort::typeid_demangle(cs.type())<< endl;
	
}
